package net.miranti;

import static net.miranti.opmov.OperationalMovement.Type.AIRCRAFT;
import static net.miranti.opmov.OperationalMovement.Type.CARGO;
import static net.miranti.opmov.OperationalMovement.Type.MAIL;
import static net.miranti.opmov.OperationalMovement.Type.PASSENGER;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import net.miranti.download.DownloadManager;
import net.miranti.opmov.OperationalMovement;
import net.miranti.opmov.client.Airport;

import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.util.PDFTextStripper;

public class Main {
	static EntityManagerFactory emf = Persistence
			.createEntityManagerFactory("default");
	static EntityManager em = emf.createEntityManager();

	public static void main(String[] args) {
		String dest = "c:\\oi";
		String sourceUrl = "http://www.infraero.gov.br";
		
		//Map<period, files>
		TreeMap<String, File> filesMap = new DownloadManager(sourceUrl, dest).downloadFiles();
		em.getTransaction().begin();
		
		//Map<period, Map<base code, base data>>
		Map<String, Map<String, String[]>> aux = new TreeMap();
		for(Entry<String, File> e : filesMap.entrySet()){
			String period = e.getKey();
			
			//Map<base code, base data>
			Map<String, String[]> airportsData = parse(e.getValue().getAbsolutePath());
			aux.put(period, airportsData);
			
			String previousPeriod = getPreviousPeriod(period); 
			airportsData = dissociate(aux.get(previousPeriod), airportsData);  
			persist(period, airportsData);
		}
		em.getTransaction().commit();
		em.close();
		emf.close();
	}

	private static Map<String, String[]> dissociate(
			Map<String, String[]> previous,
			Map<String, String[]> current) {
		
		if(previous == null)
			return current;

		Map<String, String[]> result = new TreeMap();
		for(Entry<String, String[]> e : current.entrySet()){
			String key = e.getKey();

			String[] c = e.getValue();
			String[] p = previous.get(key);
			
			String[] dissociated = Arrays.copyOf(c, c.length);
			for(int i = 2; i < c.length; i++)
				dissociated[i] = String.valueOf(new Integer(c[i]) - new Integer(p[i]));
			
			result.put(key, dissociated);
		}
		return result;
	}

	private static String getPreviousPeriod(String period) {
		String[] date = period.split("-");
		String year = date[0];
		Integer month = new Integer(date[1]) - 1;
		
		return year + "-" + (month < 10 ? "0" + month : month);
	}

	private static void persist(String period, Map<String, String[]> airportsData) {
		Map<String, Airport> airportMap = getAirportMap(new HashMap(airportsData));
		for (String[] s : airportsData.values()) {
			Airport a = airportMap.get(s[0]);

			int dom = new Integer(s[2]);
			int intl = new Integer(s[3]);
			em.persist(new OperationalMovement(AIRCRAFT, a, period, dom, intl));

			dom = new Integer(s[4]);
			intl = new Integer(s[5]);
			em.persist(new OperationalMovement(PASSENGER, a, period, dom, intl));

			dom = new Integer(s[6]);
			intl = new Integer(s[7]);
			em.persist(new OperationalMovement(CARGO, a, period, dom, intl));

			dom = new Integer(s[8]);
			intl = new Integer(s[9]);
			em.persist(new OperationalMovement(MAIL, a, period, dom, intl));
		}
	}

	private static Map<String, Airport> getAirportMap(
			Map<String, String[]> airportsData) {
		List<Airport> airports = em.createNamedQuery(
				Airport.LIST_AIRPORTS_BY_CODE).setParameter("codes",
				airportsData.keySet()).getResultList();

		HashMap<String, Airport> savedAirports = new HashMap();
		for (Airport a : airports)
			savedAirports.put(a.getCode(), a);

		airportsData.keySet().removeAll(savedAirports.keySet());

		for (String[] s : airportsData.values()) {
			Airport a = new Airport(s[0], s[1]);
			savedAirports.put(s[0], em.merge(a));
		}

		return savedAirports;
	}

	private static Map<String, String[]> parse(String filename) {
		List<String> lines = new ArrayList();
		StringReader sr = null;
		BufferedReader br = null;

		String fileContent = pdf2Text(filename);

		try {
			sr = new StringReader(fileContent);
			br = new BufferedReader(sr);

			for (String line = br.readLine(); line != null; line = br
					.readLine()) {
				if (line.startsWith("SB"))
					lines.add(line);
			}
			sr.close();
			br.close();
		} catch (FileNotFoundException ex) {
			ex.printStackTrace();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		return Collections.unmodifiableMap(parseLines(lines));
	}

	private static Map<String, String[]> parseLines(List<String> lines) {
		Map<String, String[]> airportMap = new HashMap();
		for (String line : lines) {
			try {
				String[] parsedLine = parseLine(line);
				airportMap.put(parsedLine[0], parsedLine);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}

		return airportMap;
	}

	private static String[] parseLine(String line) {
		line = removeExtraSpaces(line);

		ArrayList<String> result = new ArrayList();

		String[] split = line.split(" ");
		result.add(split[0]); // adding airport code

		String airportName = "";
		int index, n = split.length;
		for (index = 2; index < n; index++) {
			char initChar = split[index].charAt(0);
			if (initChar >= '0' && initChar <= '9')
				break;
			airportName += split[index] + " ";
		}
		result.add(airportName.trim());

		for (int i = index; i < n; i++)
			if ((i - index) % 3  != 2)
				result.add(split[i].replaceAll("\\.", ""));

		return result.toArray(new String[0]);
	}

	private static String removeExtraSpaces(String line) {
		if (line.indexOf("  ") == -1)
			return line;
		else
			return removeExtraSpaces(line.replaceAll("  ", " "));
	}

	private static String pdf2Text(String filename) {
		String parsedText = null;
		PDDocument pdDoc = null;
		COSDocument cosDoc = null;
		try {
			File f = new File(filename);
			PDFParser parser = new PDFParser(new FileInputStream(f));
			parser.parse();
			cosDoc = parser.getDocument();
			pdDoc = new PDDocument(cosDoc);
			parsedText = new PDFTextStripper().getText(pdDoc);
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				if (cosDoc != null)
					cosDoc.close();
				if (pdDoc != null)
					pdDoc.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return parsedText;
	}
}
